<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>在线JSON查看工具</title>
    <!-- JSONEditor CSS -->
    <link rel="stylesheet" href="./json/jsoneditor.min.css">
    <!-- Prism.js for syntax highlighting -->
    <link rel="stylesheet" href="./json/prism-tomorrow.min.css">
    <style>
      * {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
        font-family: 'SF Pro Display', 'PingFang SC', 'Helvetica Neue', Arial,
          sans-serif;
      }

      :root {
        --primary-bg: #e6e7ee;
        --secondary-bg: #ffffff;
        --shadow-light: #ffffff;
        --shadow-dark: #d1d9e6;
        --accent-color: #667eea;
        --accent-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        --success-color: #4ecdc4;
        --danger-color: #ff6b6b;
        --warning-color: #feca57;
        --text-primary: #2d3748;
        --text-secondary: #718096;
        --glass-bg: rgba(255, 255, 255, 0.25);
        --glass-border: rgba(255, 255, 255, 0.18);
      }

      body {
        background: var(--primary-bg);
        color: var(--text-primary);
        min-height: 100vh;
        padding: 20px;
        display: flex;
        flex-direction: column;
        align-items: center;
        transition: all 0.3s ease;
        animation: pageLoad 0.8s ease;
      }

      @keyframes pageLoad {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .container {
        width: 100%;
        max-width: 1400px;
        background: var(--primary-bg);
        border-radius: 30px;
        padding: 40px;
        box-shadow: 20px 20px 60px var(--shadow-dark),
          -20px -20px 60px var(--shadow-light);
        margin-top: 20px;
        transition: all 0.3s ease;
        animation: containerFloat 1s ease 0.2s both;
      }

      @keyframes containerFloat {
        from {
          opacity: 0;
          transform: translateY(30px) scale(0.95);
        }
        to {
          opacity: 1;
          transform: translateY(0) scale(1);
        }
      }

      .container:hover {
        box-shadow: 25px 25px 70px var(--shadow-dark),
          -25px -25px 70px var(--shadow-light);
      }

      header {
        text-align: center;
        margin-bottom: 40px;
        padding: 30px;
        background: var(--primary-bg);
        border-radius: 25px;
        box-shadow: 10px 10px 20px var(--shadow-dark),
          -10px -10px 20px var(--shadow-light);
        animation: headerSlide 0.8s ease 0.4s both;
      }

      @keyframes headerSlide {
        from {
          opacity: 0;
          transform: translateY(-30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      h1 {
        font-size: 3.2rem;
        margin-bottom: 15px;
        background: var(--accent-gradient);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
        font-weight: 700;
        animation: titleGlow 3s ease-in-out infinite alternate;
      }

      @keyframes titleGlow {
        from {
          filter: brightness(1);
        }
        to {
          filter: brightness(1.2);
        }
      }

      .subtitle {
        font-size: 1.3rem;
        color: var(--text-secondary);
        margin-bottom: 30px;
        font-weight: 500;
      }

      .input-section {
        display: flex;
        gap: 30px;
        margin-bottom: 40px;
        animation: panelsSlide 0.8s ease 0.6s both;
      }

      @keyframes panelsSlide {
        from {
          opacity: 0;
          transform: translateX(-20px);
        }
        to {
          opacity: 1;
          transform: translateX(0);
        }
      }

      .input-panel {
        flex: 1;
        background: var(--primary-bg);
        border-radius: 25px;
        padding: 30px;
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
        transition: all 0.3s ease;
        position: relative;
        overflow: hidden;
      }

      .input-panel::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.1),
          transparent
        );
        transition: left 0.8s;
      }

      .input-panel:hover::before {
        left: 100%;
      }

      .input-panel:hover {
        transform: translateY(-5px);
        box-shadow: 16px 16px 32px var(--shadow-dark),
          -16px -16px 32px var(--shadow-light);
      }

      .panel-title {
        font-size: 1.6rem;
        margin-bottom: 25px;
        color: var(--accent-color);
        display: flex;
        align-items: center;
        font-weight: 600;
      }

      .panel-title::before {
        content: attr(data-icon);
        margin-right: 12px;
        font-size: 1.8rem;
        animation: iconBounce 2s ease-in-out infinite;
      }

      @keyframes iconBounce {
        0%,
        100% {
          transform: scale(1);
        }
        50% {
          transform: scale(1.1);
        }
      }

      .file-upload {
        border: 3px dashed var(--accent-color);
        border-radius: 25px;
        padding: 50px 40px;
        text-align: center;
        transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
        margin-bottom: 25px;
        cursor: pointer;
        background: var(--primary-bg);
        box-shadow: inset 8px 8px 16px var(--shadow-dark),
          inset -8px -8px 16px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      .file-upload:hover {
        border-color: var(--success-color);
        transform: translateY(-5px) scale(1.02);
        box-shadow: inset 10px 10px 20px var(--shadow-dark),
          inset -10px -10px 20px var(--shadow-light),
          0 15px 40px rgba(102, 126, 234, 0.25), 0 5px 15px rgba(0, 0, 0, 0.1);
      }

      .file-upload.dragover {
        border-color: var(--success-color);
        background: rgba(78, 205, 196, 0.05);
        transform: scale(1.05);
        box-shadow: inset 12px 12px 24px var(--shadow-dark),
          inset -12px -12px 24px var(--shadow-light),
          0 20px 50px rgba(78, 205, 196, 0.3);
        animation: dragPulse 1s ease-in-out infinite;
      }

      @keyframes dragPulse {
        0%,
        100% {
          border-color: var(--success-color);
        }
        50% {
          border-color: var(--accent-color);
        }
      }

      .file-upload-content {
        position: relative;
        z-index: 1;
      }

      .file-upload-icon {
        font-size: 3.5rem;
        margin-bottom: 20px;
        display: block;
        animation: iconFloat 3s ease-in-out infinite;
        filter: drop-shadow(0 4px 8px rgba(102, 126, 234, 0.2));
      }

      @keyframes iconFloat {
        0%,
        100% {
          transform: translateY(0);
        }
        50% {
          transform: translateY(-10px);
        }
      }

      .file-upload-text {
        font-size: 1.4rem;
        font-weight: 600;
        color: var(--text-primary);
        margin-bottom: 10px;
        background: var(--accent-gradient);
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        background-clip: text;
      }

      .file-upload-subtext {
        font-size: 1.1rem;
        color: var(--text-secondary);
        margin-bottom: 20px;
        font-weight: 500;
      }

      .file-upload-formats {
        font-size: 0.9rem;
        color: var(--accent-color);
        font-weight: 500;
        padding: 8px 16px;
        background: rgba(102, 126, 234, 0.1);
        border-radius: 20px;
        display: inline-block;
      }

      .file-upload input[type='file'] {
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        opacity: 0;
        cursor: pointer;
        z-index: 2;
      }

      .json-textarea {
        width: 100%;
        min-height: 300px;
        padding: 20px;
        background: var(--primary-bg);
        border: none;
        border-radius: 20px;
        color: var(--text-primary);
        font-size: 14px;
        font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
        resize: vertical;
        box-shadow: inset 10px 10px 20px var(--shadow-dark),
          inset -10px -10px 20px var(--shadow-light);
        transition: all 0.3s ease;
      }

      .json-textarea:focus {
        outline: none;
        box-shadow: inset 12px 12px 24px var(--shadow-dark),
          inset -12px -12px 24px var(--shadow-light),
          0 0 0 3px rgba(102, 126, 234, 0.2);
      }

      .json-textarea::placeholder {
        color: var(--text-secondary);
        font-style: italic;
      }

      .controls {
        display: flex;
        gap: 20px;
        margin-bottom: 30px;
        justify-content: center;
        flex-wrap: wrap;
        animation: controlsSlide 0.8s ease 0.8s both;
      }

      @keyframes controlsSlide {
        from {
          opacity: 0;
          transform: translateY(20px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      button {
        background: var(--primary-bg);
        color: var(--text-primary);
        border: none;
        padding: 14px 28px;
        border-radius: 15px;
        cursor: pointer;
        font-weight: 600;
        transition: all 0.3s ease;
        font-size: 1rem;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light);
        position: relative;
        overflow: hidden;
      }

      button::before {
        content: '';
        position: absolute;
        top: 0;
        left: -100%;
        width: 100%;
        height: 100%;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.2),
          transparent
        );
        transition: left 0.5s;
      }

      button:hover::before {
        left: 100%;
      }

      button:hover {
        transform: translateY(-3px);
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
      }

      button:active {
        transform: translateY(0);
        box-shadow: inset 6px 6px 12px var(--shadow-dark),
          inset -6px -6px 12px var(--shadow-light);
      }

      .btn-primary {
        background: var(--accent-gradient);
        color: white;
        padding: 16px 32px;
        font-size: 1.1rem;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2);
      }

      .btn-primary:hover {
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2),
          0 0 30px rgba(102, 126, 234, 0.3);
      }

      .btn-success {
        background: linear-gradient(
          135deg,
          var(--success-color) 0%,
          #44a08d 100%
        );
        color: white;
        box-shadow: 8px 8px 16px var(--shadow-dark),
          -8px -8px 16px var(--shadow-light),
          inset 0 1px 0 rgba(255, 255, 255, 0.2);
      }

      .viewer-section {
        animation: viewerSlide 0.8s ease 1s both;
      }

      @keyframes viewerSlide {
        from {
          opacity: 0;
          transform: translateY(30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .viewer-container {
        background: var(--primary-bg);
        border-radius: 25px;
        padding: 30px;
        box-shadow: 12px 12px 24px var(--shadow-dark),
          -12px -12px 24px var(--shadow-light);
        min-height: 500px;
        position: relative;
      }

      .viewer-title {
        font-size: 1.8rem;
        margin-bottom: 25px;
        color: var(--accent-color);
        font-weight: 600;
        text-align: center;
      }

      #jsoneditor {
        height: 500px;
        border-radius: 15px;
        overflow: hidden;
        box-shadow: inset 8px 8px 16px var(--shadow-dark),
          inset -8px -8px 16px var(--shadow-light);
      }

      .error-message {
        color: var(--danger-color);
        margin: 20px 0;
        padding: 15px 20px;
        background: rgba(255, 107, 107, 0.1);
        border-radius: 15px;
        border-left: 4px solid var(--danger-color);
        font-weight: 600;
        animation: errorShake 0.5s ease;
      }

      @keyframes errorShake {
        0%,
        100% {
          transform: translateX(0);
        }
        25% {
          transform: translateX(-5px);
        }
        75% {
          transform: translateX(5px);
        }
      }

      .success-message {
        color: var(--success-color);
        margin: 20px 0;
        padding: 15px 20px;
        background: rgba(78, 205, 196, 0.1);
        border-radius: 15px;
        border-left: 4px solid var(--success-color);
        font-weight: 600;
        animation: successFade 0.5s ease;
      }

      @keyframes successFade {
        from {
          opacity: 0;
          transform: translateY(-10px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .stats {
        display: flex;
        gap: 20px;
        margin-top: 20px;
        justify-content: center;
        flex-wrap: wrap;
      }

      .stat-item {
        background: var(--primary-bg);
        padding: 15px 25px;
        border-radius: 15px;
        box-shadow: 6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
        text-align: center;
        min-width: 120px;
      }

      .stat-value {
        font-size: 1.5rem;
        font-weight: 700;
        color: var(--accent-color);
        display: block;
      }

      .stat-label {
        font-size: 0.9rem;
        color: var(--text-secondary);
        margin-top: 5px;
      }

      .instructions {
        background: var(--primary-bg);
        border-radius: 25px;
        padding: 30px;
        margin-top: 40px;
        box-shadow: 10px 10px 20px var(--shadow-dark),
          -10px -10px 20px var(--shadow-light);
        animation: instructionsSlide 0.8s ease 1.2s both;
      }

      @keyframes instructionsSlide {
        from {
          opacity: 0;
          transform: translateY(30px);
        }
        to {
          opacity: 1;
          transform: translateY(0);
        }
      }

      .instructions h3 {
        color: var(--accent-color);
        margin-bottom: 20px;
        font-size: 1.4rem;
        font-weight: 600;
      }

      .instructions ul {
        padding-left: 25px;
        margin-bottom: 20px;
      }

      .instructions li {
        margin-bottom: 12px;
        line-height: 1.7;
        color: var(--text-secondary);
        font-weight: 500;
      }

      .instructions p {
        color: var(--text-secondary);
        font-style: italic;
        font-weight: 500;
        padding: 15px;
        background: rgba(102, 126, 234, 0.1);
        border-radius: 15px;
        border-left: 4px solid var(--accent-color);
      }

      footer {
        margin-top: 40px;
        text-align: center;
        color: var(--text-secondary);
        font-size: 0.95rem;
        padding: 25px;
        background: var(--primary-bg);
        border-radius: 20px;
        box-shadow: 6px 6px 12px var(--shadow-dark),
          -6px -6px 12px var(--shadow-light);
        animation: footerFade 0.8s ease 1.4s both;
      }

      @keyframes footerFade {
        from {
          opacity: 0;
        }
        to {
          opacity: 1;
        }
      }

      /* 响应式设计 */
      @media (max-width: 768px) {
        .input-section {
          flex-direction: column;
        }
        
        .controls {
          flex-direction: column;
          align-items: center;
        }
        
        h1 {
          font-size: 2.5rem;
        }
        
        .container {
          padding: 20px;
        }
      }
    </style>
  </head>
  <body>
    <div class="container">
      <header>
        <h1>📄 JSON 查看工具</h1>
        <p class="subtitle">在线JSON格式化、验证和可视化工具</p>
      </header>

      <div class="input-section">
        <!-- 文件上传面板 -->
        <div class="input-panel">
          <h3 class="panel-title" data-icon="📁">选择JSON文件</h3>
          <div class="file-upload" id="fileUpload">
            <div class="file-upload-content">
              <span class="file-upload-icon">📄</span>
              <div class="file-upload-text">拖拽文件到此处</div>
              <div class="file-upload-subtext">或点击选择文件</div>
              <div class="file-upload-formats">支持 .json 文件</div>
            </div>
            <input type="file" id="fileInput" accept=".json,application/json,text/plain" />
          </div>
        </div>

        <!-- 直接输入面板 -->
        <div class="input-panel">
          <h3 class="panel-title" data-icon="✏️">直接输入JSON</h3>
          <textarea 
            id="jsonInput" 
            class="json-textarea" 
            placeholder="在此处粘贴或输入您的JSON数据...\n\n示例：\n{\n  \"name\": \"张三\",\n  \"age\": 25,\n  \"city\": \"北京\"\n}"
          ></textarea>
        </div>
      </div>

      <div class="controls">
        <button id="formatBtn" class="btn-primary">🎨 格式化JSON</button>
        <button id="validateBtn" class="btn-success">✅ 验证JSON</button>
        <button id="clearBtn">🗑️ 清空内容</button>
        <button id="copyBtn">📋 复制JSON</button>
        <button id="downloadBtn">💾 下载JSON</button>
      </div>

      <div id="messageArea"></div>

      <div class="viewer-section">
        <div class="viewer-container">
          <h3 class="viewer-title">JSON 可视化视图</h3>
          <div id="jsoneditor"></div>
        </div>
      </div>

      <div class="stats" id="statsArea" style="display: none;">
        <div class="stat-item">
          <span class="stat-value" id="sizeValue">0</span>
          <div class="stat-label">文件大小</div>
        </div>
        <div class="stat-item">
          <span class="stat-value" id="keysValue">0</span>
          <div class="stat-label">键数量</div>
        </div>
        <div class="stat-item">
          <span class="stat-value" id="depthValue">0</span>
          <div class="stat-label">嵌套深度</div>
        </div>
      </div>

      <div class="instructions">
        <h3>🔧 使用说明</h3>
        <ul>
          <li><strong>文件上传：</strong>支持拖拽或点击选择JSON文件</li>
          <li><strong>直接输入：</strong>在文本框中粘贴或输入JSON数据</li>
          <li><strong>格式化：</strong>自动美化JSON格式，便于阅读</li>
          <li><strong>验证：</strong>检查JSON语法是否正确</li>
          <li><strong>可视化：</strong>树形结构展示，支持折叠/展开</li>
          <li><strong>统计信息：</strong>显示文件大小、键数量和嵌套深度</li>
        </ul>
        <p>💡 提示：支持大型JSON文件，自动检测编码格式，提供详细的错误信息定位。</p>
      </div>

      <footer>
        <p>🚀 基于 JSONEditor 构建 | 支持大文件处理 | 完全本地化处理，保护数据隐私</p>
      </footer>
    </div>

    <!-- JSONEditor JS -->
    <script src="./json/jsoneditor.min.js"></script>
    <!-- Prism.js for syntax highlighting -->
    <script src="./json/prism-core.min.js"></script>
    <script src="./json/prism-json.min.js"></script>
    
    <script>
      // JSON编辑器实例
      let editor = null;
      let currentJsonData = null;

      // 初始化JSONEditor
      function initEditor() {
        const container = document.getElementById('jsoneditor');
        const options = {
          mode: 'view',
          modes: ['code', 'tree', 'view', 'preview'],
          search: true,
          navigationBar: true,
          statusBar: true,
          mainMenuBar: true,
          onError: function (err) {
            showMessage(err.toString(), 'error');
          },
          onModeChange: function (newMode, oldMode) {
            console.log('模式切换:', oldMode, '->', newMode);
          }
        };
        
        editor = new JSONEditor(container, options);
      }

      // 显示消息
      function showMessage(message, type = 'info') {
        const messageArea = document.getElementById('messageArea');
        const messageClass = type === 'error' ? 'error-message' : 'success-message';
        messageArea.innerHTML = `<div class="${messageClass}">${message}</div>`;
        
        // 3秒后自动清除消息
        setTimeout(() => {
          messageArea.innerHTML = '';
        }, 3000);
      }

      // 更新统计信息
      function updateStats(jsonData) {
        const statsArea = document.getElementById('statsArea');
        const sizeValue = document.getElementById('sizeValue');
        const keysValue = document.getElementById('keysValue');
        const depthValue = document.getElementById('depthValue');

        // 计算文件大小
        const jsonString = JSON.stringify(jsonData);
        const size = new Blob([jsonString]).size;
        const sizeFormatted = size < 1024 ? size + ' B' : 
                             size < 1024 * 1024 ? (size / 1024).toFixed(1) + ' KB' :
                             (size / (1024 * 1024)).toFixed(1) + ' MB';

        // 计算键数量
        function countKeys(obj) {
          let count = 0;
          if (typeof obj === 'object' && obj !== null) {
            if (Array.isArray(obj)) {
              count += obj.length;
              obj.forEach(item => count += countKeys(item));
            } else {
              count += Object.keys(obj).length;
              Object.values(obj).forEach(value => count += countKeys(value));
            }
          }
          return count;
        }

        // 计算嵌套深度
        function getDepth(obj) {
          if (typeof obj !== 'object' || obj === null) return 0;
          let maxDepth = 0;
          if (Array.isArray(obj)) {
            obj.forEach(item => {
              maxDepth = Math.max(maxDepth, getDepth(item));
            });
          } else {
            Object.values(obj).forEach(value => {
              maxDepth = Math.max(maxDepth, getDepth(value));
            });
          }
          return maxDepth + 1;
        }

        sizeValue.textContent = sizeFormatted;
        keysValue.textContent = countKeys(jsonData);
        depthValue.textContent = getDepth(jsonData);
        
        statsArea.style.display = 'flex';
      }

      // 处理JSON数据
      function processJson(jsonString) {
        try {
          const jsonData = JSON.parse(jsonString);
          currentJsonData = jsonData;
          
          // 在编辑器中显示
          editor.set(jsonData);
          
          // 更新统计信息
          updateStats(jsonData);
          
          showMessage('✅ JSON解析成功！', 'success');
          return true;
        } catch (error) {
          showMessage(`❌ JSON解析错误: ${error.message}`, 'error');
          return false;
        }
      }

      // 文件上传处理
      function handleFileUpload(file) {
        if (!file) return;
        
        const reader = new FileReader();
        reader.onload = function(e) {
          const content = e.target.result;
          document.getElementById('jsonInput').value = content;
          processJson(content);
        };
        reader.onerror = function() {
          showMessage('❌ 文件读取失败', 'error');
        };
        reader.readAsText(file);
      }

      // 事件监听器
      document.addEventListener('DOMContentLoaded', function() {
        // 初始化编辑器
        initEditor();

        // 文件输入
        const fileInput = document.getElementById('fileInput');
        const fileUpload = document.getElementById('fileUpload');
        
        fileInput.addEventListener('change', function(e) {
          const file = e.target.files[0];
          if (file) {
            handleFileUpload(file);
          }
        });

        // 拖拽上传
        fileUpload.addEventListener('dragover', function(e) {
          e.preventDefault();
          fileUpload.classList.add('dragover');
        });

        fileUpload.addEventListener('dragleave', function(e) {
          e.preventDefault();
          fileUpload.classList.remove('dragover');
        });

        fileUpload.addEventListener('drop', function(e) {
          e.preventDefault();
          fileUpload.classList.remove('dragover');
          
          const files = e.dataTransfer.files;
          if (files.length > 0) {
            handleFileUpload(files[0]);
          }
        });

        // 格式化按钮
        document.getElementById('formatBtn').addEventListener('click', function() {
          const jsonInput = document.getElementById('jsonInput');
          const content = jsonInput.value.trim();
          
          if (!content) {
            showMessage('⚠️ 请先输入JSON数据', 'error');
            return;
          }
          
          processJson(content);
        });

        // 验证按钮
        document.getElementById('validateBtn').addEventListener('click', function() {
          const jsonInput = document.getElementById('jsonInput');
          const content = jsonInput.value.trim();
          
          if (!content) {
            showMessage('⚠️ 请先输入JSON数据', 'error');
            return;
          }
          
          try {
            JSON.parse(content);
            showMessage('✅ JSON格式正确！', 'success');
          } catch (error) {
            showMessage(`❌ JSON格式错误: ${error.message}`, 'error');
          }
        });

        // 清空按钮
        document.getElementById('clearBtn').addEventListener('click', function() {
          document.getElementById('jsonInput').value = '';
          editor.set({});
          currentJsonData = null;
          document.getElementById('statsArea').style.display = 'none';
          document.getElementById('messageArea').innerHTML = '';
          showMessage('🗑️ 内容已清空', 'success');
        });

        // 复制按钮
        document.getElementById('copyBtn').addEventListener('click', function() {
          if (!currentJsonData) {
            showMessage('⚠️ 没有可复制的JSON数据', 'error');
            return;
          }
          
          const jsonString = JSON.stringify(currentJsonData, null, 2);
          navigator.clipboard.writeText(jsonString).then(function() {
            showMessage('📋 JSON已复制到剪贴板', 'success');
          }).catch(function() {
            // 降级方案
            const textArea = document.createElement('textarea');
            textArea.value = jsonString;
            document.body.appendChild(textArea);
            textArea.select();
            document.execCommand('copy');
            document.body.removeChild(textArea);
            showMessage('📋 JSON已复制到剪贴板', 'success');
          });
        });

        // 下载按钮
        document.getElementById('downloadBtn').addEventListener('click', function() {
          if (!currentJsonData) {
            showMessage('⚠️ 没有可下载的JSON数据', 'error');
            return;
          }
          
          const jsonString = JSON.stringify(currentJsonData, null, 2);
          const blob = new Blob([jsonString], { type: 'application/json' });
          const url = URL.createObjectURL(blob);
          
          const a = document.createElement('a');
          a.href = url;
          a.download = 'formatted.json';
          document.body.appendChild(a);
          a.click();
          document.body.removeChild(a);
          URL.revokeObjectURL(url);
          
          showMessage('💾 JSON文件已下载', 'success');
        });

        // 文本框实时验证
        const jsonInput = document.getElementById('jsonInput');
        let validationTimeout;
        jsonInput.addEventListener('input', function() {
          clearTimeout(validationTimeout);
          validationTimeout = setTimeout(() => {
            const content = jsonInput.value.trim();
            if (content) {
              try {
                JSON.parse(content);
                jsonInput.style.borderLeft = '4px solid var(--success-color)';
              } catch (error) {
                jsonInput.style.borderLeft = '4px solid var(--danger-color)';
              }
            } else {
              jsonInput.style.borderLeft = 'none';
            }
          }, 500);
        });
      });
    </script>
  </body>
</html>